﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media.Effects;
using Cjc.ChromiumBrowserDemo.Effects;
using Cjc.ChromiumBrowserDemo.Properties;
using System.Collections.ObjectModel;

namespace Cjc.ChromiumBrowserDemo
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		private string baseTitle;
		private BindingBase addressBinding;
		private int zoom = 100;

		public MainWindow()
			: this( Settings.Default.DefaultUrl )
		{
		}

		public MainWindow( string url )
		{
			Effects = EffectsHelper.GetEffects();
			Console = new ObservableCollection<string>();

			InitializeComponent();

			address.GotFocus += delegate { address.SelectAll(); };
			Loaded += delegate { address.Focus(); };
			Closing += delegate { Settings.Default.Save(); };

			// Preserve binding; we'll need to set it again after input
			addressBinding = BindingOperations.GetBinding( address, TextBox.TextProperty );
			baseTitle = Title;

			browser.Ready += delegate
			{
				browser.BeginLoading += delegate { loading.Visibility = Visibility.Visible; };
				browser.FinishLoading += delegate { loading.Visibility = Visibility.Collapsed; };
				browser.CreateObject( "ReturnProxy" );
				browser.SetObjectCallback( "ReturnProxy", "SendValue" );
			};

			browser.Source = url;
		}

		public IDictionary<string, ShaderEffect> Effects { get; private set; }
		public ObservableCollection<string> Console { get; private set; }

        private void Button_Click( object sender, RoutedEventArgs e )
        {
			var url = GetUrl();

			if ( url.StartsWith( "javascript:" ) )
			{
				browser.ExecuteJavascript( url.Replace( "javascript:", "" ), "" );
			}
			else
			{
				browser.Navigate( GetUrl() );
				browser.Focus();
			}

			// Replace binding (since Mode=OneWay, text input will clear binding)
			address.SetBinding( TextBox.TextProperty, addressBinding );
		}

		private void browser_ReceiveTitle( object sender, Cjc.ChromiumBrowser.WebBrowser.ContentEventArgs e )
		{
			if ( string.IsNullOrEmpty( e.FrameName ) ) this.Title = e.Content + " - " + baseTitle;
		}

		private void browser_Status( object sender, Cjc.ChromiumBrowser.WebBrowser.StatusEventArgs e )
		{
			status.Items.Insert( 0, e.Message );

			while ( status.Items.Count > 100 ) status.Items.RemoveAt( status.Items.Count - 1 );
		}

		private void openTransparent_Click( object sender, RoutedEventArgs e )
		{
			var childWindow = new MainWindow( GetUrl() );
			childWindow.Show();
		}

		private void back_Click( object sender, RoutedEventArgs e )
		{
			browser.GotoHistoryOffset( -1 );
		}

		private void forward_Click( object sender, RoutedEventArgs e )
		{
			browser.GotoHistoryOffset( 1 );
		}

		private void Default_Click( object sender, RoutedEventArgs e )
		{
			Settings.Default.DefaultUrl = GetUrl();
		}

		private string GetUrl()
		{
			var source = address.Text.Trim();

			return source.Contains( ":" ) ? source : "http://" + source;
		}

		private void zoomIn_Click( object sender, RoutedEventArgs e )
		{
			browser.SetZoom( Math.Min( zoom += 10, 500 ) );
		}

		private void zoomOut_Click( object sender, RoutedEventArgs e )
		{
			browser.SetZoom( Math.Max( zoom -= 10, 10 ) );
		}

		private void execute_Click( object sender, RoutedEventArgs e )
		{
			Console.Add( "> " + command.Text );

			var futureValue = browser.ExecuteJavascriptWithResult( command.Text );

			command.Text = "";

			try
			{
				var value = (object)futureValue.GetWithTimeout( 1000 ).Value();
				var enumerable = value as IEnumerable<CjcAwesomiumWrapper.JSValue>;
				var dictionary = value as IDictionary<string, CjcAwesomiumWrapper.JSValue>;

				var strValue = ( dictionary != null )
					? string.Join( ", ", dictionary.Select( v => string.Format( "{0} = {1}", v.Key, v.Value.Value() ) ).ToArray() )
					: ( enumerable != null )
						? string.Join( ", ", enumerable.Select( v => v.ToString() ).ToArray() )
						: ( value != null ) ? value.ToString() : null;

				var typeName = ( dictionary != null )
					? "Dictionary"
					: ( enumerable != null )
						? "Collection"
						: ( value != null ) ? value.GetType().Name : null;

				Console.Add( string.Format( "{0}{1}", strValue, ( typeName != null ) ? string.Format( " ({0})", typeName ) : "[null]" ) );
			}
			catch ( Exception ex )
			{
				Console.Add( string.Format( "[ERROR: {0}]", ex.Message ) );
			}
		}
	}
}
